﻿using System;
using System.CodeDom;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using Microsoft.CSharp;

namespace Script_Text_Editor_WPF_Edition.Library
{
    #region DynamicCodeCompiler

    class DynamicCodeCompiler
    {
        Assembly _assembly;
        CompilerParameters _compilerParameters = new CompilerParameters();

        public DynamicCodeCompiler()
        {
            _compilerParameters.ReferencedAssemblies.Add("System.dll");
            _compilerParameters.GenerateExecutable = false;
            _compilerParameters.GenerateInMemory = true;
        }

        /// <summary>
        /// 获取或设置要编译的代码
        /// </summary>
        public string SourceCode { get; set; }

        /// <summary>
        /// 编译选项
        /// </summary>
        public CompilerParameters CompilerParameters
        {
            get
            {
                return _compilerParameters;
            }
            set
            {
                _compilerParameters = value;
            }
        }

        public Assembly Compile()
        {
            CSharpCodeProvider provider = new CSharpCodeProvider();
            CompilerResults results = provider.CompileAssemblyFromSource(_compilerParameters, SourceCode);

            if (results.Errors.HasErrors)
            {
                string errorText = string.Empty;

                foreach (CompilerError err in results.Errors)
                    errorText += String.Format("{0}{1}: {2}", Environment.NewLine, err.Line, err.ErrorText);

                throw new Exception(errorText);
            }

            return results.CompiledAssembly;
        }
    }

    #endregion DynamicCodeCompiler

    class DynamicCodeWrapper : ILibrary
    {
        NETWrapper _netWrapper;
        bool _hasError;

        /// <summary>
        /// 获取当前类型的内部编号
        /// </summary>
        public static int Index
        {
            get { return 1; }
        }

        #region Interface methods

        public string GetLibraryInfo()
        {
            return _netWrapper.GetLibraryInfo();
        }

        public string GetSupportExtensions()
        {
            return _netWrapper.GetSupportExtensions();
        }

        public string GetStringBreakLineChar()
        {
            return _netWrapper.GetStringBreakLineChar();
        }

        public bool GetCanMakeNewLine()
        {
            return _netWrapper.GetCanMakeNewLine();
        }

        public string GetNewLineBreakChar()
        {
            return _netWrapper.GetNewLineBreakChar();
        }

        public string GetStringCollection(byte[] file)
        {
            return _netWrapper.GetStringCollection(file);
        }

        public byte[] SetStringCollection(string file)
        {
            return _netWrapper.SetStringCollection(file);
        }

        #endregion Interface methods

        #region Wrapper

        public DynamicCodeWrapper(string filePath, Encoding encoding)
        {
            StreamReader sr = new StreamReader(filePath, encoding, true);
            string code = sr.ReadToEnd();
            sr.Close();

            Init(code);
        }

        public DynamicCodeWrapper(string code)
        {
            Init(code);
        }

        public NETWrapper NETWrapper
        {
            get { return _netWrapper; }
        }

        public bool HasError
        {
            get { return _hasError; }
        }

        private void Init(string code)
        {
            DynamicCodeCompiler compiler = new DynamicCodeCompiler();
            compiler.SourceCode = code;

            foreach (string line in code.Replace(Environment.NewLine, "\n").Split('\n'))
            {
                if (line.StartsWith(@"//@Ref:"))
                    compiler.CompilerParameters.ReferencedAssemblies.Add(line.Split(':')[1]);
            }

            try
            {
                _netWrapper = new NETWrapper(compiler.Compile());
            }
            catch (Exception e)
            {
                _hasError = true;
                MessageBox.Show(e.Message);
            }
        }

        #endregion Wrapper
    }
}